<template>
  <div class="bpm-chart" :class="isFullScreen ? 'fullScreen' : ''">
    <div :id="popoverId" />
    <a-spin :spinning="spinning" class="flow-graph-spin-box">
      <avic-error-card v-if="error" :error-message="error" />
      <avic-flow-canvas
        ref="flowCanvas"
        :graph-option="graphOption"
        :data="flowData"
        @node-click="nodeClick"
        @user-defined-click="userDefinedClick"
      />
      <!--节点流程图-->
      <avic-bpm-chart-child :deployment-id="deploymentIdChild" :select-visible="selectVisibleChild" @closeChild="closeChild" />
      <!--节点子流程流程跟踪--->
      <father-track
        v-if="fatherVisible"
        :title="fatherTitle"
        :show-bpm-open-form-but="showBpmOpenFormBut"
        :entry-id="fatherEntryId"
        :visible="fatherVisible"
        @closeFather="closeFather"
      />
      <!--节点子过程跟踪--->
      <BpmPiFatherTrack v-if="fatherBpmpiVisible" :title="fatherTitle" :entry-id="fatherEntryId" @closeFather="closeFather" />
      <!-- <sub-flow-list v-if="subListVisible" :sub-data="subList" @close="closeSubFlow" @confirm="selectSubFlow" /> -->
      <AvicModal
        :visible="openModal"
        title="配置的人员信息"
        width="800px"
        height="520px"
        :centered="true"
        :mask-closable="false"
        :footer="null"
        @cancel="closeModal"
      >
        <a-list :data-source="nodeUserDefinedList">
          <template #renderItem="{ item }">
            <a-list-item>{{ item.userName }} （ {{ item.deptName }} ）</a-list-item>
          </template>
        </a-list>
      </AvicModal>
    </a-spin>
  </div>
</template>

<script>
import { Spin } from 'ant-design-vue';
import AvicErrorCard from '@/components/error-card/index.vue';
import AvicBpmFlowCanvas from '../bpmpi-canvas/index.vue';
import AvicBpmChartChild from '@/views/avic/bpm/flowdetail/components/bpm-content/AvicBpmChartChild/index.vue';
// import FatherTrack from './FatherTrack.vue';
// import BpmPiFatherTrack from './BpmPiFatherTrack.vue';
// import SubFlowList from '@/views/avic/bpm/flowdetail/components/bpm-buttons-modal/SubFlowList.vue';
import bpmUtils from '@/views/avic/bpm/bpmutils/FlowUtils';
import { httpAction } from '@/api/avic/bpm/FlowUtilApi';
import { getBpmPiInstanceCandidatesByInstanceId, getBpmPiHistoryActivityList } from '@/api/avic/bpmpi/BpmPiInstanceApi';
function validNodePosition(node) {
  if (node.position && typeof node.position.x !== 'undefined' && typeof node.position.y !== 'undefined') {
    return true;
  }
  return false;
}
/** 两点连线的接入点
 * 目标节点相对起始节点的位置
 */
const fixedLinePort = {
  // 正左
  L: {
    sourcePort: 'p_top',
    targetPort: 'p_top'
  },
  // 正右
  R: {
    sourcePort: 'p_top',
    targetPort: 'p_top'
  },
  // 正上
  B: {
    sourcePort: 'p_right',
    targetPort: 'p_right'
  },
  // 正下
  T: {
    sourcePort: 'p_right',
    targetPort: 'p_right'
  },
  // 左上
  LT: {
    sourcePort: 'p_top',
    targetPort: 'p_right'
  },
  // 左下
  LB: {
    sourcePort: 'p_bottom',
    targetPort: 'p_right'
  },
  // 右上
  RT: {
    sourcePort: 'p_top',
    targetPort: 'p_left'
  },
  // 右下
  RB: {
    sourcePort: 'p_bottom',
    targetPort: 'p_left'
  },
  // 上左
  TL: {
    sourcePort: 'p_left',
    targetPort: 'p_bottom'
  },
  // 上右
  TR: {
    sourcePort: 'p_right',
    targetPort: 'p_bottom'
  },
  // 下左
  BL: {
    sourcePort: 'p_left',
    targetPort: 'p_top'
  },
  // 下右
  BR: {
    sourcePort: 'p_right',
    targetPort: 'p_top'
  }
};
/**
 * 计算节点连线的连接点（最佳路径）
 */
function calcLinePort(lineEdges) {
  const result = {
    sourcePort: 'p_top',
    targetPort: 'p_top'
  };
  if (!lineEdges || lineEdges.length < 2 || !validNodePosition(lineEdges[0] || !validNodePosition(lineEdges[1]))) {
    return result;
  }
  const source = lineEdges[0];
  const target = lineEdges[1];
  const offsetX = target.position.x - source.position.x;
  const offsetY = target.position.y - source.position.y;
  let positionOffsetType = '';
  // 起点在终点的左右(模糊)
  if (Math.abs(offsetX) > Math.abs(offsetY)) {
    positionOffsetType += offsetX >= 0 ? 'R' : 'L';
    if (offsetY !== 0) {
      positionOffsetType += offsetY > 0 ? 'B' : 'T';
    }
  } else {
    positionOffsetType += offsetY > 0 ? 'B' : 'T';
    if (offsetX !== 0) {
      positionOffsetType += offsetX > 0 ? 'R' : 'L';
    }
  }
  return fixedLinePort[positionOffsetType];
}

export default {
  name: 'AvicBpmX6ChartTemplate',
  components: {
    ASpin: Spin,
    AvicFlowCanvas: AvicBpmFlowCanvas,
    AvicBpmChartChild,
    FatherTrack: defineAsyncComponent(() => import('./FatherTrack.vue')),
    AvicErrorCard,
    BpmPiFatherTrack: defineAsyncComponent(() => import('./BpmPiFatherTrack.vue'))
  },
  props: {
    // 流程图加载参数 ,包括 url 请求地址  parameter 加载参数 method 请类型
    flowParam: {
      type: Object,
      required: true,
      default: null
    },
    // 点击流程节点类型
    type: {
      type: String,
      required: false,
      default: null
    },
    contentLoading: {
      type: Boolean,
      default: true
    },
    showBpmOpenFormBut: {
      type: Boolean,
      required: false,
      default: true
    },
    openProcessTracking: {
      type: Boolean,
      required: false,
      default: false
    },
    showFullScreen: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      flowQueryUrl: '/api/bpm/design/getProcessJson/v1',
      flowId: '4028b8817d320895017d320c37d40009',
      flowType: 2,
      spinning: false,
      graphOption: {
        panning: false,
        grid: 1
      },
      error: '',
      data: null,
      flowData: {},
      instanceData: {},
      // 获取流程图数据
      iconTypeParam: {
        url: `${bpmUtils.baseurl}/business/getIconType/v1`,
        method: 'post'
      },
      // 流程跳转
      getValidateDestActivity: {
        url: `${bpmUtils.baseurl}/business/validateDestActivity/v1`,
        method: 'post'
      },
      getcoordinate: {
        url: `${bpmUtils.baseurl}/clientbpmdisplayaction/getcoordinate/v1`,
        method: 'post'
      },
      startExecutionId: '', // 流程跳转
      fatherVisible: false, // 节点流程状态
      fatherBpmpiVisible: false, // 节点过程状态
      fatherEntryId: '', // 节点流程id
      subListVisible: false, // 节点流程列表状态
      subList: [], // 子表列表
      subprocess: [],
      fatherTitle: '',
      deploymentIdChild: '', // 字流程 deploymentId
      chartHeight: '300px',
      selectVisibleChild: false, // 节点流程 是否显示
      arrayObj: [],
      popoverId: '', // 气泡框父容器
      getUserDefinedParam: {
        url: `${bpmUtils.baseurl}/business/getUserDefined/v1`,
        method: 'post'
      },
      userDefinedList: [],
      openModal: false,
      nodeUserDefinedList: [],
      isFullScreen: false,
      nodeCandidatesList: [],
      historyActivityList: []
    };
  },
  computed: {
    entryId() {
      return this.flowParam.parameter.entryId || this.flowParam.parameter.processInstanceId || '';
    }
  },
  mounted() {
    // this.refreshFlowChart();
    // eslint-disable-next-line func-names
    this.$nextTick(function () {
      this.chartHeight = 'auto';
    });
    this.popoverId = `popoverId${this.getRandomAlphaNum(4)}`;
  },
  methods: {
    getPopupContainer(trigger) {
      return trigger.parentElement;
    },
    // 刷新流程图
    async refreshFlowChart() {
      if (this.flowParam && this.flowParam.parameter && this.flowParam.url) {
        this.spinning = true;
        this.$emit('beforeLoadFlowChart', this.flowParam);
        const promises = [this.loadDataProcessJson(), this.getNodeRunInfo(), this.getHistoryActivityList()];
        Promise.allSettled(promises).then(() => {
          this.drawChart();
          this.spinning = false;
        });
      }
    },
    getNodeRunInfo() {
      this.nodeCandidatesList = [];
      return new Promise((resolve) => {
        getBpmPiInstanceCandidatesByInstanceId(this.entryId).then((res) => {
          this.nodeCandidatesList = res.data;
          resolve();
        });
      });
    },
    getHistoryActivityList() {
      this.historyActivityList = [];
      return new Promise((resolve) => {
        getBpmPiHistoryActivityList(this.entryId).then((res) => {
          this.historyActivityList = res.data;
          resolve();
        });
      });
    },
    // 加载流程数据
    loadDataProcessJson() {
      return httpAction(this.flowParam.url, this.flowParam.parameter)
        .then((res) => {
          if (res.success === true) {
            this.data = res.data;
            if (res.data && res.data.subprocess) {
              this.subprocess = res.data.subprocess;
            }
            this.error = '';
          } else {
            this.error = '过程加载失败';
          }
          // this.spinning = false;
          this.$emit('afterLoadFlowChart', res);
        })
        .catch(() => {
          this.spinning = false;
          this.$emit('afterLoadFlowChart', null);
          this.error = '过程加载失败';
        });
    },
    // 画图
    async drawChart() {
      if (!this.data?.processModel) return;
      const { processModel, currActivities, histActivities, subprocess, historyLines } = this.data;
      const { edge, graph, node } = processModel;
      if (this.type === 'dostepuserdefined') {
        const userDefinedListRes = await httpAction(this.getUserDefinedParam.url, this.entryId, this.getUserDefinedParam.method);
        if (userDefinedListRes && userDefinedListRes.data) {
          this.userDefinedList = userDefinedListRes.data;
        }
      }
      node.forEach((item) => {
        item.data.popconfirmId = this.popoverId; // 存入id
        item.data.entryId = this.entryId; // 存入实例id 获取节点的流程处理信息
        item.data.nodeStatus = 'norun';
        if (this.type === 'dostepuserdefined' && Object.keys(this.userDefinedList).includes(item.data.name)) {
          item.data.userDefinedStatus = 'defined';
          item.data.userDefinedList = this.userDefinedList[item.data.name];
          item.attrs = {
            body: {
              class: 'user-defined-border'
            }
          };
        }

        if (histActivities && histActivities.includes(item.data.name)) {
          item.data.nodeStatus = 'over';
          item.data.showTooltipName = item.data.name;
        }
        if (currActivities && currActivities.includes(item.data.name)) {
          item.data.nodeStatus = 'run';
          item.data.showTooltipName = item.data.name;
        }
        if (subprocess && subprocess[item.data.name]) {
          if (currActivities && currActivities.includes(item.data.name)) {
            item.data.nodeStatus = 'subrun';
          } else if (histActivities && histActivities.includes(item.data.name)) {
            item.data.nodeStatus = 'subover';
          }
          item.data.showTooltipName = item.data.name;
        }
        this.nodeCandidatesList.forEach((nodeCandidateItem) => {
          if (item.data.name === nodeCandidateItem.nodeId) {
            item.data.candidate = nodeCandidateItem;
          }
        });
        this.historyActivityList.forEach((activityItem) => {
          if (item.data.name === activityItem.activityName) {
            item.data.activity = activityItem;
          }
        });
      });
      edge.forEach((item) => {
        const line = [];
        node.forEach((tim) => {
          if (tim.id === item.source.cell) {
            line.unshift(tim.data.name);
          } else if (tim.id === item.target.cell) {
            line.push(tim.data.name);
          }
        });
        if (currActivities && currActivities.includes(item.data.to)) {
          item.data.edgeStatus = 'runing';
        } else {
          if (historyLines && historyLines.includes(line.join(','))) {
            item.data.edgeStatus = 'run';
          } else {
            item.data.edgeStatus = 'norun';
          }
        }
      });
      // 将模板图中没有的流转线加到实例图的edge集合
      historyLines &&
        historyLines.forEach((item) => {
          if (item && item.split(',').length === 2) {
            const linePoints = item.split(',');
            const sourceNode = linePoints[0];
            const targetNode = linePoints[1];
            let sourceNodeId = '';
            let targetNodeId = '';
            const jumpLineNodes = [];
            node.forEach((flowNode) => {
              if (flowNode.data.name === sourceNode) {
                sourceNodeId = flowNode.id;
                jumpLineNodes.unshift(flowNode);
              }
              if (flowNode.data.name === targetNode) {
                targetNodeId = flowNode.id;
                jumpLineNodes.push(flowNode);
              }
            });
            // 校验模板图中有没有的流转线
            // eslint-disable-next-line max-len
            const currentLine = edge.find(
              (templateEdge) => templateEdge.source.cell === sourceNodeId && templateEdge.target.cell === targetNodeId
            );
            if (!currentLine) {
              const { sourcePort, targetPort } = calcLinePort(jumpLineNodes);
              edge.push({
                shape: 'edge',
                source: {
                  cell: sourceNodeId,
                  port: sourcePort
                },
                target: {
                  cell: targetNodeId,
                  port: targetPort
                },
                data: {
                  edgeStatus: 'jump'
                }
              });
            }
          }
        });
      this.flowData = { edge, graph, node };
      if (this.$refs.flowCanvas) {
        this.$refs.flowCanvas.initFlow(this.flowData);
      }
      this.$emit('loaded', this.flowData);
    },

    // 节点点击事件
    nodeClick({ node }) {
      if (this.openProcessTracking) {
        this.childClick(node);
        this.drawAct(this.flowParam.parameter.processInstanceId, node);
      }
      this.$emit('node-click', { graph: this.flowData, node });
    },
    userDefinedClick({ node }) {
      this.nodeUserDefinedList = node.data.userDefinedList ? JSON.parse(node.data.userDefinedList) : [];
      this.openModal = true;
    },
    closeModal() {
      this.openModal = false;
    },
    /**
     * 获取流程点击事件coordinate
     */
    async getcoordinateByEntryId(entryId) {
      if (entryId) {
        const res = await httpAction(
          this.getcoordinate.url,
          {
            processInstanceId: entryId
          },
          this.getcoordinate.method
        );
        return new Promise((resolve) => {
          if (res.success) {
            resolve(res);
          } else {
            resolve(res);
          }
        });
      }
      return true;
    },
    /**
     * 创建流程节点点击事件
     */
    async drawAct(entryId, cell) {
      const node = cell.store.data;
      const res = await this.getcoordinateByEntryId(entryId);
      if (res.success) {
        for (const key in res.data) {
          const activity = res.data[key];
          const { activityName } = activity;
          if (activity.isCurrent === 'true') {
            this.arrayObj.push(node);
          }
          if (activityName === node.data.name) {
            const { activityAlias } = activity;
            const { isCurrent } = activity;
            const { over } = activity;
            const { executionId } = activity;
            const isAlone = activity.executionAlone;
            if (bpmUtils.notNull(node.data.name)) {
              if (isCurrent === 'true') {
                if (this.type === 'dosupplement') {
                  this.$emit('clickNode', activityName, executionId);
                }
                if (this.type === 'doglobaljump') {
                  this.dojump(activityName, executionId, node, entryId, isCurrent, activityAlias, isAlone, cell);
                }
                if (this.type === 'dowithdraw') {
                  this.$emit('clickNode', activityName, executionId);
                }
                // 拿回部分待办
                if (this.type === 'dowithdrawpart') {
                  this.$emit('clickNode', activityName, executionId);
                }
              } else {
                if (this.type === 'doglobaljump') {
                  this.dojump(activityName, executionId, node, entryId, isCurrent, activityAlias, isAlone, cell);
                }
                if (this.type === 'doretreattowant' && over === 'true') {
                  this.$emit('clickNode', activityName);
                }
              }
              if (this.type === 'dostepuserdefined') {
                this.$emit('clickNode', activityName, executionId, entryId, over, isCurrent);
              }
            }
          }
        }
      }
    },
    // 处理节点流程节点点击事件
    childClick(node) {
      const child = node.store.data;
      // 流程跳转禁止弹窗
      if (this.type === 'doglobaljump') return;
      if (child.data.name === 'sub-process' || ['subrun', 'subover'].includes(child.data.nodeStatus)) {
        if (this.subprocess) {
          if (this.subprocess[child.data.name]) {
            if (this.subprocess[child.data.name].entryId) {
              if (child.data.nodeType === 'piflow') {
                // 流程类型的过程节点才可以打开子流程
                this.fatherTitle = `${child.data.alias}节点子流程`;
                this.fatherVisible = true;
              } else if (child.data.nodeType === 'pisubprocess') {
                // 流程类型的过程节点才可以打开子流程
                this.fatherTitle = `${child.data.alias}节点子过程`;
                this.fatherBpmpiVisible = true;
              }
              this.fatherEntryId = this.subprocess[child.data.name].entryId;
            } else if (this.subprocess[child.data.name].length > 1) {
              this.subListVisible = true;
              this.subList = this.subprocess[child.data.name];
            } else if (this.subprocess[child.data.name].length > 0 && this.subprocess[child.data.name][0].entryId) {
              if (child.data.nodeType === 'piflow') {
                // 流程类型的过程节点才可以打开子流程
                this.fatherTitle = `${child.data.alias}节点子流程`;
                this.fatherVisible = true;
              } else if (child.data.nodeType === 'pisubprocess') {
                this.fatherTitle = `${child.data.alias}节点子过程`;
                // 流程类型的过程节点才可以打开子流程
                this.fatherBpmpiVisible = true;
              }
              this.fatherEntryId = this.subprocess[child.data.name][0].entryId;
            } else if (child.store.data.deploymentId) {
              this.deploymentIdChild = child.data.deploymentId;
              this.selectVisibleChild = true;
            }
          } else {
            if (child.deploymentId) {
              this.deploymentIdChild = child.data.deploymentId;
              this.selectVisibleChild = true;
            }
          }
        } else if (child.deploymentId) {
          this.deploymentIdChild = child.data.deploymentId;
          this.selectVisibleChild = true;
        }
      }
    },
    /** 选择指定的节点流程图打开 */
    selectSubFlow(entryId) {
      if (entryId) {
        this.fatherTitle = '节点流程';
        this.fatherVisible = true;
        this.fatherEntryId = entryId;
      }
    },
    /** 关闭选择节点流程弹窗 */
    closeSubFlow() {
      this.subListVisible = false;
    },
    // 流程跳转
    // eslint-disable-next-line max-params
    async dojump(activityName, executionId, node, processInstanceId, isCurrent, activityAlias, isAlone, cell) {
      const values = this.data.processModel.node;
      // 只有一个当前节点，默认是开始节点
      if (isAlone) {
        if (isCurrent === 'true') {
          this.startExecutionId = executionId;
          cell.setData({ jumpStatus: 'start' });
          cell.setAttrs({
            body: {
              class: 'jump-start-node'
            }
          });
          return;
        }
      } else {
        if (isCurrent === 'true') {
          this.startExecutionId = executionId;
          // this.mxEditor.graph.setCellStyles('imageBorder', 'blue', [node.getCell()]);
          // TODO:设置节点样式
          for (const key in values) {
            const now = values[key];
            if (now.id !== node.id) {
              const nowCell = this.$refs.flowCanvas.graph.getCellById(now.id);
              nowCell.setData({ jumpStatus: 'no' });
              nowCell.setAttrs({
                body: {
                  class: 'jump-no-node'
                }
              });
            }
          }
          cell.setData({ jumpStatus: 'start' });
          cell.setAttrs({
            body: {
              class: 'jump-start-node'
            }
          });
          return;
        }
      }
      if (!bpmUtils.notNull(this.startExecutionId)) {
        this.$message.error('请您先选择一个当前节点作为流程跳转的起始节点');
        return;
      }
      // Added in 01-16
      const rst = ref(null);
      if (bpmUtils.notNull(this.startExecutionId)) {
        rst.value = await this.validateDestActivity(processInstanceId, this.startExecutionId, activityName);
      }
      // else {
      //   rst.value = await this.validateDestActivity(processInstanceId, executionId, activityName);
      // }
      if (rst.value.data.flag === 'failed') {
        this.$message.error('无法跳转到所选节点，请您重新选择');
        return;
      }
      // 分支跳转
      if (bpmUtils.notNull(this.startExecutionId)) {
        // eslint-disable-next-line no-param-reassign
        executionId = this.startExecutionId;
      }
      this.$emit('clickNode', activityName, executionId);
    },
    // 流程跳转
    async validateDestActivity(processInstanceId, executionId, activityName) {
      const res = await httpAction(
        this.getValidateDestActivity.url,
        {
          procinstDbid: processInstanceId,
          executionId,
          activityName
        },
        this.getValidateDestActivity.method
      );
      return new Promise((resolve) => {
        if (res.success) {
          resolve(res);
        } else {
          resolve(res);
        }
      });
    },
    closeChild() {
      this.selectVisibleChild = false;
    },
    closeFather() {
      this.fatherVisible = false;
      this.fatherBpmpiVisible = false;
      this.fatherEntryId = '';
    },
    getRandomAlphaNum(len) {
      let rdmString = '';
      // eslint-disable-next-line newline-per-chained-call
      for (; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));
      return rdmString.substr(0, len);
    },
    /**
     * 进入全屏模式
     */
    fullScreen() {
      this.isFullScreen = true;
    },

    /**
     * 退出全屏模式
     *
     */
    exitFullScreen() {
      this.isFullScreen = false;
    }
  }
};
</script>

<style lang="less" scoped>
.main {
  border: 1px solid #d6dce3;
}
.bpm-chart {
  // position: relative;
  overflow: auto;
  height: 100%;
  background: #f7f8fa url('@views/avic/bpm/flowdetail/assets/bpm-chart-bg/flow_bg.png');
}
.fullScreen-btn {
  position: absolute;
  left: 96%;
  top: 30px;
  z-index: 999;
  cursor: pointer;
  font-size: 16px;
  margin-right: 10px;
}
.fullScreen {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 200;
  height: 100%;
  max-height: 100% !important;
}
.bpm-popover-box {
  display: inline-block;
}
.bpm-node-box {
  display: flex;
  width: 600px;
  /*max-height: 140px;*/
  /*overflow: auto;*/
  .ant-spin-container {
    width: 100%;
    height: 100%;
  }
  .table-box {
    display: flex;
    flex: 1;
    width: 600px;
    .node {
      flex: 1;
      .name {
        width: 20px;
      }
    }
  }
  :deep(.table-content) {
    min-height: 86px;
    max-height: 224px;
    overflow: hidden;
  }
}
.flow-track-box {
  width: 100%;
  min-width: 400px;
  height: auto !important;
  text-align: center;
}
.graph-button-box {
  .ant-btn-group {
    .ant-btn {
      padding: 0;
    }
  }
}
:deep(.ant-spin-nested-loading) {
  height: 100%;
  display: block;
}
:deep(.ant-spin-container) {
  height: 100%;
  display: block;
}
</style>
